package com.example.detectivedemo.infrastructure.generic;

import com.example.detectivedemo.domain.generic.GenericEntity;
import com.example.detectivedemo.domain.generic.GenericRepository;
import ohos.data.DatabaseHelper;
import ohos.data.rdb.*;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * 通用DAO类
 * 基于鸿蒙RDB数据库实现通用的CRUD操作
 * @param <T> 实体类型
 */
public abstract class GenericDao<T extends GenericEntity> implements GenericRepository<T> {
    
    private static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00205, "GenericDao");
    
    protected RdbStore rdbStore;
    protected DatabaseHelper databaseHelper;
    protected final String tableName;
    protected final Class<T> entityClass;
    
    /**
     * 构造函数
     * @param databaseHelper 数据库助手
     * @param tableName 表名
     * @param entityClass 实体类
     */
    public GenericDao(DatabaseHelper databaseHelper, String tableName, Class<T> entityClass) {
        this.databaseHelper = databaseHelper;
        this.tableName = tableName;
        this.entityClass = entityClass;
        initRdbStore();
    }
    
    /**
     * 初始化RDB存储
     */
    private void initRdbStore() {
        try {
            RdbStoreConfig config = RdbStoreConfig.newDefaultConfig("generic_app.db");
            rdbStore = databaseHelper.getRdbStore(config, 1, new RdbOpenCallback() {
                @Override
                public void onCreate(RdbStore store) {
                    createTable(store);
                }
                
                @Override
                public void onUpgrade(RdbStore store, int oldVersion, int newVersion) {
                    // 升级逻辑可以在这里实现
                }
            }, null);
        } catch (Exception e) {
            HiLog.error(LABEL, "Failed to initialize RdbStore: %{public}s", e.getMessage());
        }
    }
    
    /**
     * 创建表（由子类实现）
     * @param store RDB存储
     */
    protected abstract void createTable(RdbStore store);
    
    /**
     * 将实体转换为ValuesBucket
     * @param entity 实体
     * @return ValuesBucket
     */
    protected abstract ValuesBucket entityToValuesBucket(T entity);
    
    /**
     * 将结果集转换为实体
     * @param resultSet 结果集
     * @return 实体
     */
    protected abstract T resultSetToEntity(ResultSet resultSet);
    
    @Override
    public T save(T entity) {
        try {
            if (entity.getId() == null || entity.getId().isEmpty()) {
                return null;
            }
            
            // 检查记录是否存在
            String[] columns = new String[]{"id"};
            ResultSet resultSet = rdbStore.query(tableName, columns, "id = ?", new String[]{entity.getId()}, null, null, null);
            boolean exists = resultSet != null && resultSet.goToFirstRow();
            if (resultSet != null) {
                resultSet.close();
            }
            
            ValuesBucket values = entityToValuesBucket(entity);
            if (exists) {
                // 更新记录
                rdbStore.update(tableName, values, "id = ?", new String[]{entity.getId()});
            } else {
                // 插入记录
                rdbStore.insert(tableName, values);
            }
            
            return entity;
        } catch (Exception e) {
            HiLog.error(LABEL, "Failed to save entity: %{public}s", e.getMessage());
            return null;
        }
    }
    
    @Override
    public Optional<T> findById(String id) {
        try {
            String[] columns = getAllColumnNames();
            ResultSet resultSet = rdbStore.query(tableName, columns, "id = ?", new String[]{id}, null, null, null);
            
            if (resultSet != null && resultSet.goToFirstRow()) {
                T entity = resultSetToEntity(resultSet);
                resultSet.close();
                return Optional.ofNullable(entity);
            }
            
            if (resultSet != null) {
                resultSet.close();
            }
        } catch (Exception e) {
            HiLog.error(LABEL, "Failed to find entity by id: %{public}s", e.getMessage());
        }
        return Optional.empty();
    }
    
    @Override
    public List<T> findAll() {
        try {
            String[] columns = getAllColumnNames();
            ResultSet resultSet = rdbStore.query(tableName, columns, null, null, null, null, null);
            return resultSetToList(resultSet);
        } catch (Exception e) {
            HiLog.error(LABEL, "Failed to find all entities: %{public}s", e.getMessage());
            return new ArrayList<>();
        }
    }
    
    @Override
    public List<T> findByCondition(String condition) {
        try {
            String[] columns = getAllColumnNames();
            ResultSet resultSet = rdbStore.query(tableName, columns, condition, null, null, null, null);
            return resultSetToList(resultSet);
        } catch (Exception e) {
            HiLog.error(LABEL, "Failed to find entities by condition: %{public}s", e.getMessage());
            return new ArrayList<>();
        }
    }
    
    @Override
    public T update(T entity) {
        return save(entity); // 复用save方法
    }
    
    @Override
    public boolean deleteById(String id) {
        try {
            int count = rdbStore.delete(tableName, "id = ?", new String[]{id});
            return count > 0;
        } catch (Exception e) {
            HiLog.error(LABEL, "Failed to delete entity: %{public}s", e.getMessage());
            return false;
        }
    }
    
    @Override
    public long count() {
        try {
            String[] columns = new String[]{"COUNT(*)"};
            ResultSet resultSet = rdbStore.query(tableName, columns, null, null, null, null, null);
            
            if (resultSet != null && resultSet.goToFirstRow()) {
                long count = resultSet.getLong(0);
                resultSet.close();
                return count;
            }
            
            if (resultSet != null) {
                resultSet.close();
            }
        } catch (Exception e) {
            HiLog.error(LABEL, "Failed to count entities: %{public}s", e.getMessage());
        }
        return 0;
    }
    
    @Override
    public List<T> batchSave(List<T> entities) {
        try {
            for (T entity : entities) {
                save(entity);
            }
            return entities;
        } catch (Exception e) {
            HiLog.error(LABEL, "Failed to batch save entities: %{public}s", e.getMessage());
            return new ArrayList<>();
        }
    }
    
    /**
     * 将结果集转换为实体列表
     * @param resultSet 结果集
     * @return 实体列表
     */
    protected List<T> resultSetToList(ResultSet resultSet) {
        List<T> entities = new ArrayList<>();
        
        if (resultSet != null) {
            try {
                while (resultSet.goToNextRow()) {
                    T entity = resultSetToEntity(resultSet);
                    entities.add(entity);
                }
            } catch (Exception e) {
                HiLog.error(LABEL, "Failed to convert resultSet to list: %{public}s", e.getMessage());
            } finally {
                resultSet.close();
            }
        }
        
        return entities;
    }
    
    /**
     * 获取所有列名（通过反射获取）
     * @return 列名数组
     */
    private String[] getAllColumnNames() {
        List<String> columnNames = new ArrayList<>();
        Field[] fields = entityClass.getDeclaredFields();
        
        for (Field field : fields) {
            field.setAccessible(true);
            columnNames.add(field.getName());
        }
        
        return columnNames.toArray(new String[0]);
    }
}